import { useState, useEffect, useCallback, useRef } from 'react';
import { invoke } from '@tauri-apps/api/core';
import { listen, UnlistenFn } from '@tauri-apps/api/event';
import {
  ConnectionState,
  ConnectionConfig,
  ServerMessage,
  TerminalSession,
  WebShareProxyInfo,
} from '../types';

export function useRitermConnection() {
  const [connectionState, setConnectionState] = useState<ConnectionState>({
    isConnected: false,
    connectedTerminals: [],
    activeProxies: [],
    peers: [],
  });
  const [isConnecting, setIsConnecting] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const unlistenFns = useRef<UnlistenFn[]>([]);

  // Setup event listeners
  useEffect(() => {
    const setupListeners = async () => {
      const listeners: UnlistenFn[] = [];

      // Listen for connection events
      const unlistenConnected = await listen<ServerMessage>(
        'riterm://connected',
        (event) => {
          const { nodeId, ticket } = event.payload;
          setConnectionState(prev => ({
            ...prev,
            nodeId,
            ticket,
            isConnected: true,
          }));
          setError(null);
        }
      );
      listeners.push(unlistenConnected);

      const unlistenDisconnected = await listen<ServerMessage>(
        'riterm://disconnected',
        () => {
          setConnectionState(prev => ({
            ...prev,
            isConnected: false,
            connectedTerminals: [],
            activeProxies: [],
            peers: [],
          }));
        }
      );
      listeners.push(unlistenDisconnected);

      // Listen for terminal events
      const unlistenTerminalCreated = await listen<ServerMessage>(
        'riterm://terminal-created',
        (event) => {
          const { sessionId } = event.payload;
          setConnectionState(prev => ({
            ...prev,
            connectedTerminals: [...prev.connectedTerminals, {
              sessionId,
              name: undefined,
              status: 'active',
              createdAt: Date.now() / 1000,
              lastActivity: Date.now() / 1000,
              size: { rows: 24, cols: 80 },
            }],
          }));
        }
      );
      listeners.push(unlistenTerminalCreated);

      const unlistenTerminalOutput = await listen<ServerMessage>(
        'riterm://terminal-output',
        (event) => {
          // This would be handled by individual terminal components
          console.log('Terminal output:', event.payload);
        }
      );
      listeners.push(unlistenTerminalOutput);

      const unlistenTerminalStatus = await listen<ServerMessage>(
        'riterm://terminal-status',
        (event) => {
          const { sessionId, status } = event.payload;
          setConnectionState(prev => ({
            ...prev,
            connectedTerminals: prev.connectedTerminals.map(term =>
              term.sessionId === sessionId ? { ...term, status } : term
            ),
          }));
        }
      );
      listeners.push(unlistenTerminalStatus);

      const unlistenTerminalStateChanged = await listen<ServerMessage>(
        'riterm://terminal-state-changed',
        (event) => {
          const { terminals } = event.payload;
          setConnectionState(prev => ({
            ...prev,
            connectedTerminals: terminals,
          }));
        }
      );
      listeners.push(unlistenTerminalStateChanged);

      // Listen for node events
      const unlistenNodeJoined = await listen<ServerMessage>(
        'riterm://node-joined',
        (event) => {
          const { nodeId } = event.payload;
          setConnectionState(prev => ({
            ...prev,
            peers: [...prev.peers, nodeId],
          }));
        }
      );
      listeners.push(unlistenNodeJoined);

      const unlistenNodeLeft = await listen<ServerMessage>(
        'riterm://node-left',
        (event) => {
          const { nodeId } = event.payload;
          setConnectionState(prev => ({
            ...prev,
            peers: prev.peers.filter(peer => peer !== nodeId),
          }));
        }
      );
      listeners.push(unlistenNodeLeft);

      // Listen for web share events
      const unlistenWebShareStarted = await listen<ServerMessage>(
        'riterm://web-share-started',
        (event) => {
          const { localPort, publicPort } = event.payload;
          setConnectionState(prev => ({
            ...prev,
            activeProxies: [...prev.activeProxies, {
              localPort,
              publicPort,
              nodeId: 'unknown',
              status: 'active',
              createdAt: Date.now() / 1000,
            }],
          }));
        }
      );
      listeners.push(unlistenWebShareStarted);

      const unlistenWebShareStopped = await listen<ServerMessage>(
        'riterm://web-share-stopped',
        (event) => {
          const { publicPort } = event.payload;
          setConnectionState(prev => ({
            ...prev,
            activeProxies: prev.activeProxies.filter(proxy => proxy.publicPort !== publicPort),
          }));
        }
      );
      listeners.push(unlistenWebShareStopped);

      // Listen for errors
      const unlistenError = await listen<ServerMessage>(
        'riterm://error',
        (event) => {
          setError(event.payload.message);
        }
      );
      listeners.push(unlistenError);

      unlistenFns.current = listeners;
    };

    setupListeners();

    return () => {
      unlistenFns.current.forEach(unlisten => unlisten());
    };
  }, []);

  // Connect to remote CLI
  const connect = useCallback(async (config: ConnectionConfig) => {
    setIsConnecting(true);
    setError(null);

    try {
      await invoke('connect_to_cli', { config });
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to connect');
    } finally {
      setIsConnecting(false);
    }
  }, []);

  // Disconnect from remote CLI
  const disconnect = useCallback(async () => {
    try {
      await invoke('disconnect_from_cli');
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to disconnect');
    }
  }, []);

  // Create terminal
  const createTerminal = useCallback(async (
    sessionId: string,
    shellPath?: string,
    name?: string
  ) => {
    try {
      await invoke('create_terminal', { sessionId, shellPath, name });
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to create terminal');
    }
  }, []);

  // Send terminal input
  const sendTerminalInput = useCallback(async (sessionId: string, data: number[]) => {
    try {
      console.log(`[Hook Debug] sendTerminalInput called:`, {
        sessionId,
        dataLength: data.length,
        data: data.slice(0, 10)
      });
      // Convert number[] to Uint8Array to match backend expectations
      const uint8Array = new Uint8Array(data);
      const invokeParams = { sessionId, data: Array.from(uint8Array) };
      console.log(`[Hook Debug] Invoking send_terminal_input with params:`, invokeParams);
      await invoke('send_terminal_input', invokeParams);
    } catch (err) {
      console.error(`[Hook Debug] sendTerminalInput error:`, err);
      setError(err instanceof Error ? err.message : 'Failed to send terminal input');
    }
  }, []);

  // Resize terminal
  const resizeTerminal = useCallback(async (
    sessionId: string,
    rows: number,
    cols: number
  ) => {
    try {
      await invoke('resize_terminal', { sessionId, rows, cols });
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to resize terminal');
    }
  }, []);

  // Close terminal
  const closeTerminal = useCallback(async (sessionId: string) => {
    try {
      await invoke('close_terminal', { sessionId });
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to close terminal');
    }
  }, []);

  // Rename terminal
  const renameTerminal = useCallback(async (
    sessionId: string,
    newName?: string
  ) => {
    try {
      await invoke('rename_terminal', { sessionId, newName });
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to rename terminal');
    }
  }, []);

  // Send web share
  const sendWebShare = useCallback(async (localPort: number, publicPort: number) => {
    try {
      await invoke('send_web_share', { localPort, publicPort });
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to share web service');
    }
  }, []);

  // Send web unshare
  const sendWebUnshare = useCallback(async (publicPort: number) => {
    try {
      await invoke('send_web_unshare', { publicPort });
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to stop web sharing');
    }
  }, []);

  return {
    connectionState,
    isConnecting,
    error,
    connect,
    disconnect,
    createTerminal,
    sendTerminalInput,
    resizeTerminal,
    closeTerminal,
    renameTerminal,
    sendWebShare,
    sendWebUnshare,
  };
}